using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.Collections.Generic;

public class Payment : AccountItem
{
    private int paymentId;
    private int accountId;
    private PaymentType type;
    private PaymentDirection direction;
    private string reference;

    public int PaymentId
    {
        get { return paymentId; }
        set { paymentId = value; }
    }

    public int AccountId
    {
        get { return accountId; }
        set { accountId = value; }
    }

    public PaymentType Type
    {
        get { return type; }
        set { type = value; }
    }

    public PaymentDirection Direction
    {
        get { return direction; }
        set { direction = value; }
    }

    public string Reference
    {
        get { return reference; }
        set { reference = value; }
    }

    protected Payment() { }

    protected Payment(
        int paymentId, 
        int accountId, 
        PaymentType type, 
        PaymentDirection direction,
        decimal amount,
        string reference,
        DateTime paymentDate,
        DateTime createDate,
        DateTime updateDate)
        : base(paymentDate, createDate, updateDate, amount)
    {
        this.paymentId = paymentId;
        this.accountId = accountId;
        this.type = type;
        this.direction = direction;
        this.reference = reference;
    }

    protected Payment(
        int paymentId,
        int accountId,
        PaymentType type,
        PaymentDirection direction,
        decimal amount,
        string reference,
        DateTime paymentDate,
        DateTime createDate,
        DateTime updateDate,
        string accountCode,
        string accountTitle)
        : this(
        paymentId,
        accountId,
        type,
        direction,
        amount,
        reference,
        paymentDate,
        createDate,
        updateDate)
    {
        this.AccountCode = accountCode;
        this.AccountTitle = accountTitle;
    }

    internal static Payment Create(
        PaymentType type, 
        PaymentDirection direction, 
        decimal amount,
        DateTime paymentDate,
        string reference,
        int accountId)
    {
        int paymentId;
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("PaymentCreate", connection);
            command.CommandType = CommandType.StoredProcedure;

            if (direction == PaymentDirection.Recieve)
            {
                // Invert amount if payment has been recieved.
                amount *= -1;
            }

            command.Parameters.AddWithValue("type", type);
            command.Parameters.AddWithValue("amount", amount);
            command.Parameters.AddWithValue("paymentDate", paymentDate);
            command.Parameters.AddWithValue("reference", reference);
            command.Parameters.AddWithValue("accountId", accountId);
            command.Parameters.Add("paymentId", SqlDbType.Int).Direction = ParameterDirection.Output;

            connection.Open();
            command.ExecuteNonQuery();
            connection.Close();

            paymentId = (int)command.Parameters["paymentId"].Value;
        }

        return new Payment(
            paymentId, accountId, type, direction,
            amount, reference, paymentDate, DateTime.Now, DateTime.Now);
    }

    public static Payment FromReader(SqlDataReader reader)
    {
        decimal amount = (decimal)reader["Amount"];
        PaymentDirection direction = (amount < 0) ? PaymentDirection.Recieve : PaymentDirection.Send;
        if (direction == PaymentDirection.Recieve)
        {
            // Invert negative recieve value.
            amount *= -1;
        }

        Payment payment = new Payment(
            (int)reader["PaymentId"],
            (int)reader["AccountId"],
            (PaymentType)reader["TypeFlag"],
            direction, amount,
            (string)reader["Reference"],
            (DateTime)reader["PaymentDate"],
            (DateTime)reader["CreateDate"],
            (DateTime)reader["UpdateDate"],
            (string)reader["AccountCode"],
            (string)reader["AccountTitle"]);

        return payment;
    }

    internal static List<Payment> Fetch()
    {
        List<Payment> paymentList = new List<Payment>();
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("PaymentFetch", connection);
            command.CommandType = CommandType.StoredProcedure;

            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                paymentList.Add(FromReader(reader));
            }
            connection.Close();
        }
        return paymentList;
    }

    internal static List<Payment> Fetch(int accountId)
    {
        List<Payment> paymentList = new List<Payment>();
        using (SqlConnection connection = new SqlConnection(Settings.ConnectionStrings.AccountsDatabase))
        {
            SqlCommand command = new SqlCommand("PaymentFetchByAccountId", connection);
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddWithValue("accountId", accountId);

            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                paymentList.Add(Payment.FromReader(reader));
            }
            connection.Close();
        }
        return paymentList;
    }
}
